#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

#include "list.h"

#include "commonpool.h"

#define __DEBUG				0

struct CommonPoolSession
{
	time_t				last_excited_secondstamp ;
	
	size_t				session_ctx_size ;
	
	struct list_head		session_list_node ;
	
	char				session_ctx[0] ;
} ;

#define COMMONPOOL_STATUS_INIT				0
#define COMMONPOOL_STATUS_RUNNING			1
#define COMMONPOOL_STATUS_RUNNING_THREAD_EXCEPTION	2
#define COMMONPOOL_STATUS_STOPING			3
#define COMMONPOOL_STATUS_STOPED			4
#if __DEBUG
static char				*sg_commonpool_status_str[] = { "INIT" , "RUNNING" , "RUNNING_THREAD_EXCEPTION" , "STOPING" , "STOPED" } ;
#endif

#define COMMONPOOL_MIN_IDLE_SESSIONS_COUNT_DEFAULT	1
#define COMMONPOOL_MAX_IDLE_SESSIONS_COUNT_DEFAULT	5
#define COMMONPOOL_MAX_SESSIONS_COUNT_DEFAULT		20
#define COMMONPOOL_MAX_IDLE_TIMEVAL_DEFAULT		5*60 /* s */
#define COMMONPOOL_WATCH_IDLE_TIMEVAL_DEFAULT		60 /* s */
#define COMMONPOOL_INSPECT_TIMEVAL_DEFAULT		1000 /* us */

struct CommonPool
{
	unsigned char			status ;
	
	struct CommonPoolCallback	callback ;
	
	unsigned char			assistant_thread_enable ;
	size_t				min_idle_sessions_count ;
	size_t				max_idle_sessions_count ;
	size_t				max_sessions_count ;
	size_t				max_idle_timeval ; /* s */
	size_t				watch_idle_timeval ; /* s */
	size_t				inspect_timeval ; /* us */
	
	void				*user_data ;
	
	size_t				idle_sessions_count ;
	struct list_head		idle_sessions_list ;
	size_t				working_sessions_count ;
	struct list_head		working_sessions_list ;
	
	pthread_t			watch_idle_thread ;
	pthread_mutex_t			fetch_mutex ;
} ;

static int LockCommonPoolFetchMutex( struct CommonPool *pool )
{
	int		nret = 0 ;
	
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : before lock fetch mutex\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ ); fflush(stdout);
#endif
	nret = pthread_mutex_lock( & (pool->fetch_mutex) ) ;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : after lock fetch mutex , return[%d]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , nret ); fflush(stdout);
#endif
	return nret;
}

static int UnlockCommonPoolFetchMutex( struct CommonPool *pool )
{
	int		nret = 0 ;
	
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : before unlock fetch mutex\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ ); fflush(stdout);
#endif
	nret = pthread_mutex_unlock( & (pool->fetch_mutex) ) ;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : after unlock fetch mutex , return[%d]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , nret ); fflush(stdout);
#endif
	return nret;
}

static int CreateCommonPoolSession( struct CommonPool *pool , struct CommonPoolSession **pp_session )
{
	size_t				session_total_size ;
	struct CommonPoolSession	*session = NULL ;
	int				nret = 0 ;
	
	session_total_size = sizeof(struct CommonPoolSession) + pool->callback.session_ctx_size ;
	session = (struct CommonPoolSession *)malloc( session_total_size ) ;
	if( session == NULL )
	{
		return COMMONPOOL_ERROR_ALLOC;
	}
	memset( session , 0x00 , session_total_size );
	
	session->last_excited_secondstamp = time( NULL ) ;
	
	nret = pool->callback.pfuncInitSessionContext( pool , session->session_ctx ) ;
	if( nret )
	{
		return COMMONPOOL_ERROR_CREATE_SESSION;
	}
	
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s - create session[%p]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session ); fflush(stdout);
#endif
	(*pp_session) = session ;
	return 0;
}

static int DestroyCommonPoolSession( struct CommonPool *pool , struct CommonPoolSession *session )
{
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s - destroy session[%p]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session ); fflush(stdout);
#endif
	pool->callback.pfuncCleanSessionContext( pool , session->session_ctx );
	
	free( session );
	
	return 0;
}

void *CommonPoolAssistantThread( void *arg )
{
	struct CommonPool		*pool = (struct CommonPool *)arg ;
	time_t				last_watch_idle_secondstamp ;
	time_t				secondstamp ;
	struct CommonPoolSession	*session = NULL ;
	int				nret = 0 ;
	
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s - start : pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
	if( pool->status != COMMONPOOL_STATUS_RUNNING )
	{
		pool->status = COMMONPOOL_STATUS_RUNNING_THREAD_EXCEPTION ;
		return NULL;
	}
	
	if( pool->callback.pfuncWatchingSessions == NULL )
	{
		pool->status = COMMONPOOL_STATUS_RUNNING_THREAD_EXCEPTION ;
		return NULL;
	}
	
	last_watch_idle_secondstamp = time( NULL ) ;
	for( ; ; )
	{
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s - loop : pool[%p]->status[%s] working_sessions_count[%ld]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] , pool->working_sessions_count ); fflush(stdout);
#endif
		
		if( pool->status == COMMONPOOL_STATUS_STOPING && pool->working_sessions_count == 0 )
		{
			pool->status = COMMONPOOL_STATUS_STOPED ;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s - loop : set pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
			break;
		}
		
		if( pool->watch_idle_timeval > 0 )
		{
			secondstamp = time( NULL ) ;
			if( secondstamp - last_watch_idle_secondstamp >= pool->watch_idle_timeval )
			{
				if( pool->callback.pfuncWatchingSessions )
				{
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s - loop : call pfuncWatchingSessions\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ ); fflush(stdout);
#endif
					nret = pool->callback.pfuncWatchingSessions( pool ) ;
					if( nret < 0 )
					{
						pool->status = COMMONPOOL_STATUS_RUNNING_THREAD_EXCEPTION ;
						break;
					}
				}
				
				last_watch_idle_secondstamp = secondstamp ;
			}
		}
		
		if( pool->max_idle_timeval > 0 )
		{
			nret = LockCommonPoolFetchMutex( pool ) ;
			if( nret )
			{
				pool->status = COMMONPOOL_STATUS_RUNNING_THREAD_EXCEPTION ;
				return NULL;
			}
			/* pthread mutex */
			{
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s - loop : pool->min_idle_sessions_count[%ld] idle_sessions_count[%ld] max_idle_sessions_count[%ld]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool->min_idle_sessions_count , pool->idle_sessions_count , pool->max_idle_sessions_count ); fflush(stdout);
#endif
				if( pool->idle_sessions_count < pool->min_idle_sessions_count && pool->idle_sessions_count+pool->working_sessions_count < pool->max_sessions_count )
				{
					nret = CreateCommonPoolSession( pool , & session ) ;
					if( nret )
					{
					}
					else
					{
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s - loop : set working_sessions_count[%zu]->[%zu]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool->working_sessions_count , pool->working_sessions_count+1 ); fflush(stdout);
#endif
						list_add_tail( & (session->session_list_node) , & (pool->idle_sessions_list) );
						pool->idle_sessions_count++;
					}
				}
				else if( pool->idle_sessions_count > pool->max_idle_sessions_count )
				{
					session = list_last_entry_or_null( & (pool->idle_sessions_list) , struct CommonPoolSession , session_list_node ) ;
					if( session == NULL )
					{
						UnlockCommonPoolFetchMutex( pool );
						pool->status = COMMONPOOL_STATUS_RUNNING_THREAD_EXCEPTION ;
						return NULL;
					}
					
					secondstamp = time( NULL ) ;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s - loop : compare secondstamp[%ld] - session[%p]->last_excited_secondstamp[%ld] = [%ld] >= pool->max_idle_timeval[%ld] ?\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , secondstamp , session , session->last_excited_secondstamp , secondstamp-session->last_excited_secondstamp , pool->max_idle_timeval ); fflush(stdout);
#endif
					if( secondstamp - session->last_excited_secondstamp >= pool->max_idle_timeval )
					{
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s - loop : idle_sessions_count[%zu]->[%zu]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool->idle_sessions_count , pool->idle_sessions_count-1 ); fflush(stdout);
#endif
						list_del( & (session->session_list_node) );
						pool->idle_sessions_count--;
						
						DestroyCommonPoolSession( pool , session );
					}
				}
			}
			nret = UnlockCommonPoolFetchMutex( pool ) ;
			if( nret )
			{
				pool->status = COMMONPOOL_STATUS_RUNNING_THREAD_EXCEPTION ;
				return NULL;
			}
		}
		
		usleep( pool->inspect_timeval );
	}
	
	return NULL;
}

struct CommonPool *CreateCommonPool( struct CommonPoolCallback *callback , size_t comm_pool_callback_size )
{
	struct CommonPool	*pool = NULL ;
	
	if( comm_pool_callback_size != sizeof(struct CommonPoolCallback) )
		return NULL;
	
	pool = (struct CommonPool *)malloc( sizeof(struct CommonPool) ) ;
	if( pool == NULL )
		return NULL;
	memset( pool , 0x00 , sizeof(struct CommonPool) );
	INIT_LIST_HEAD( & (pool->idle_sessions_list) );
	INIT_LIST_HEAD( & (pool->working_sessions_list) );
	
	memcpy( & (pool->callback) , callback , sizeof(struct CommonPoolCallback) );
	pool->min_idle_sessions_count = COMMONPOOL_MIN_IDLE_SESSIONS_COUNT_DEFAULT ;
	pool->max_idle_sessions_count = COMMONPOOL_MAX_IDLE_SESSIONS_COUNT_DEFAULT ;
	pool->max_sessions_count = COMMONPOOL_MAX_SESSIONS_COUNT_DEFAULT ;
	pool->max_idle_timeval = COMMONPOOL_MAX_IDLE_TIMEVAL_DEFAULT ;
	pool->watch_idle_timeval = COMMONPOOL_WATCH_IDLE_TIMEVAL_DEFAULT ;
	pool->inspect_timeval = COMMONPOOL_WATCH_IDLE_TIMEVAL_DEFAULT ;
	
	pthread_mutex_init( & (pool->fetch_mutex) , NULL );
	
	pool->status = COMMONPOOL_STATUS_INIT ;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : min_idle_sessions_count[%zu] max_idle_sessions_count[%zu] max_sessions_count[%zu] max_idle_timeval[%zu] watch_idle_timeval[%ld] inspect_timeval[%ld] pool->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool->min_idle_sessions_count , pool->max_idle_sessions_count , pool->max_sessions_count , pool->max_idle_timeval , pool->watch_idle_timeval , pool->inspect_timeval , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
	
	return pool;
}

int StartCommonPool( struct CommonPool *pool )
{
	struct CommonPoolSession	*session = NULL ;
	size_t				session_no ;
	int				nret = 0 ;
	
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
	if( pool->status == COMMONPOOL_STATUS_INIT )
		;
	else
		return COMMONPOOL_ERROR_POOL_STATUS;
	
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : min_idle_sessions_count[%zu] max_idle_sessions_count[%zu] max_sessions_count[%zu] max_idle_timeval[%zu] watch_idle_timeval[%ld] inspect_timeval[%ld]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool->min_idle_sessions_count , pool->max_idle_sessions_count , pool->max_sessions_count , pool->max_idle_timeval , pool->watch_idle_timeval , pool->inspect_timeval ); fflush(stdout);
#endif
	for( session_no = 0 ; session_no < pool->min_idle_sessions_count ; session_no++ )
	{
		nret = CreateCommonPoolSession( pool , & session ) ;
		if( nret )
		{
			return nret;
		}
		
		list_add_tail( & (session->session_list_node) , & (pool->idle_sessions_list) );
		pool->idle_sessions_count++;
	}
	
	pool->status = COMMONPOOL_STATUS_RUNNING ;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : set pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
	
	if( pool->assistant_thread_enable )
	{
		nret = pthread_create( & (pool->watch_idle_thread) , NULL , & CommonPoolAssistantThread , pool ) ;
		if( nret )
		{
			pool->status = COMMONPOOL_STATUS_STOPED ;
			return COMMONPOOL_ERROR_CREATE_WATCHING_THREAD;
		}
	}
	
	return COMMONPOOL_ERROR_SUCCESS;
}

int StopCommonPool( struct CommonPool *pool )
{
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
	if( pool->status == COMMONPOOL_STATUS_RUNNING )
		;
	else
		return COMMONPOOL_ERROR_POOL_STATUS;
	
	if( pool->assistant_thread_enable )
	{
		pool->status = COMMONPOOL_STATUS_STOPING ;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : set pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
		
		for( ; ; )
		{
			if( pool->status == COMMONPOOL_STATUS_STOPED || pool->status == COMMONPOOL_STATUS_RUNNING_THREAD_EXCEPTION )
			{
				pool->status = COMMONPOOL_STATUS_STOPED ;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : set pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
				pthread_join( pool->watch_idle_thread , NULL );
				break;
			}
			
			usleep( 100*1000 );
		}
	}
	else
	{
#if 0
		pool->status = COMMONPOOL_STATUS_STOPING ;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : set pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
		
		for( ; ; )
		{
			if( pool->working_sessions_count == 0 )
			{
				break;
			}
			
			usleep( 100*1000 );
		}
		
#endif
		pool->status = COMMONPOOL_STATUS_STOPED ;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : set pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
	}
	
	return COMMONPOOL_ERROR_SUCCESS;
}

int DestroyCommonPool( struct CommonPool *pool )
{
	struct CommonPoolSession	*session = NULL ;
	struct CommonPoolSession	*next_session = NULL ;
	
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
	if( pool->status == COMMONPOOL_STATUS_STOPED )
		;
	else
		return COMMONPOOL_ERROR_POOL_STATUS;
	
	list_for_each_entry_safe( session , next_session , & (pool->idle_sessions_list) , struct CommonPoolSession , session_list_node )
	{
		list_del( & (session->session_list_node) );
		pool->idle_sessions_count--;
		
		DestroyCommonPoolSession( pool , session );
	}
	
	free( pool );
	
	return COMMONPOOL_ERROR_SUCCESS;
}

int EnableAssistantThread( struct CommonPool *pool , unsigned char assistant_thread_enable )
{
	pool->assistant_thread_enable = assistant_thread_enable ;
	
	return 0;
}

int SetCommonPoolMinIdleSessionsCount( struct CommonPool *pool , size_t min_idle_sessions_count )
{
	pool->min_idle_sessions_count = min_idle_sessions_count ;
	if( pool->min_idle_sessions_count < 0 )
		pool->min_idle_sessions_count = 0 ;
	
	return COMMONPOOL_ERROR_SUCCESS;
}

int SetCommonPoolMaxIdleSessionsCount( struct CommonPool *pool , size_t max_idle_sessions_count )
{
	pool->max_idle_sessions_count = max_idle_sessions_count ;
	if( pool->max_idle_sessions_count < pool->min_idle_sessions_count )
		pool->max_idle_sessions_count = pool->min_idle_sessions_count ;
	
	return COMMONPOOL_ERROR_SUCCESS;
}

int SetCommonPoolMaxSessionsCount( struct CommonPool *pool , size_t max_sessions_count )
{
	pool->max_sessions_count = max_sessions_count ;
	
	return COMMONPOOL_ERROR_SUCCESS;
}

int SetCommonPoolMaxIdleTimeval( struct CommonPool *pool , size_t max_idle_timeval )
{
	pool->max_idle_timeval = max_idle_timeval ;
	if( pool->max_idle_timeval < 0 )
		pool->max_idle_timeval = 0 ;
	
	return COMMONPOOL_ERROR_SUCCESS;
}

int SetCommonPoolWatchIdleTimeval( struct CommonPool *pool , size_t watch_idle_timeval )
{
	pool->watch_idle_timeval = watch_idle_timeval ;
	if( pool->watch_idle_timeval < 1 )
		pool->watch_idle_timeval = 1 ;
	
	return COMMONPOOL_ERROR_SUCCESS;
}

int SetCommonPoolInspectTimeval( struct CommonPool *pool , size_t inspect_timeval )
{
	pool->inspect_timeval = inspect_timeval ;
	if( pool->inspect_timeval < 1 )
		pool->inspect_timeval = 1 ;
	
	return COMMONPOOL_ERROR_SUCCESS;
}

void SetCommonPoolUserData( struct CommonPool *pool , void *user_data )
{
	pool->user_data = user_data ;
	return;
}

void *GetCommonPoolUserData( struct CommonPool *pool )
{
	return pool->user_data;
}

void IdleSession2Working( struct CommonPool *pool , struct CommonPoolSession *session )
{
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : before idle2working , session->session_list_node[%p][%p]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session->session_list_node.prev,session->session_list_node.next ); fflush(stdout);
#endif
	list_del( & (session->session_list_node) );
	pool->idle_sessions_count--;
	list_add_tail( & (session->session_list_node) , & (pool->working_sessions_list) );
	pool->working_sessions_count++;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : after idle2working , session->session_list_node[%p][%p]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session->session_list_node.prev,session->session_list_node.next ); fflush(stdout);
#endif
	
	return;
}

void WorkingSession2Idle( struct CommonPool *pool , struct CommonPoolSession *session )
{
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : before working2idle , session->session_list_node[%p][%p]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session->session_list_node.prev,session->session_list_node.next ); fflush(stdout);
#endif
	list_del( & (session->session_list_node) );
	pool->working_sessions_count--;
	
	if( pool->status != COMMONPOOL_STATUS_RUNNING )
	{
		DestroyCommonPoolSession( pool , session );
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : after DestroyCommonPoolSession\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ ); fflush(stdout);
#endif
	}
	else
	{
		LIST_ADD( & (session->session_list_node) , & (pool->idle_sessions_list) );
		pool->idle_sessions_count++;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : after working2idle , session->session_list_node[%p][%p]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session->session_list_node.prev,session->session_list_node.next ); fflush(stdout);
#endif
	}
	
	return;
}

int FetchCommonPoolSession( struct CommonPool *pool , void **session_ctx )
{
	struct CommonPoolSession	*session = NULL ;
	int				nret = 0 ;
	
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
	if( pool->status == COMMONPOOL_STATUS_RUNNING )
		;
	else
		return COMMONPOOL_ERROR_POOL_STATUS;
	
	nret = LockCommonPoolFetchMutex( pool ) ;
	if( nret )
		return COMMONPOOL_ERROR_MUTEX;
	/* pthread mutex */
	{
		if( pool->idle_sessions_count > 0 )
		{
			session = list_first_entry_or_null( & (pool->idle_sessions_list) , struct CommonPoolSession , session_list_node ) ;
			if( session == NULL )
			{
				UnlockCommonPoolFetchMutex( pool );
				return COMMONPOOL_ERROR_INTERNAL;
			}
			
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : fetch session[%p] last_excited_secondstamp[%ld] idle_sessions_count[%zu]->[%zu] working_sessions_count[%zu]->[%zu]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session , session->last_excited_secondstamp , pool->idle_sessions_count , pool->idle_sessions_count-1 , pool->working_sessions_count , pool->working_sessions_count+1 ); fflush(stdout);
#endif
			IdleSession2Working( pool , session );
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : fetch session[%p] IdleSession2Working\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session ); fflush(stdout);
#endif
		}
		else if( pool->idle_sessions_count+pool->working_sessions_count < pool->max_sessions_count )
		{
			nret = CreateCommonPoolSession( pool , & session ) ;
			if( nret )
			{
				UnlockCommonPoolFetchMutex( pool );
				return nret;
			}
			
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : create session[%p] last_excited_secondstamp[%ld] idle_sessions_count[%zu]->[%zu] working_sessions_count[%zu]->[%zu]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session , session->last_excited_secondstamp , pool->idle_sessions_count , pool->idle_sessions_count-1 , pool->working_sessions_count , pool->working_sessions_count+1); fflush(stdout);
#endif
			list_add_tail( & (session->session_list_node) , & (pool->working_sessions_list) );
			pool->working_sessions_count++;
		}
		else
		{
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : too many sessions , idle_sessions_count[%zu] working_sessions_count[%zu]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool->idle_sessions_count , pool->working_sessions_count ); fflush(stdout);
#endif
			UnlockCommonPoolFetchMutex( pool );
			return COMMONPOOL_ERROR_TOO_MANY_SESSIONS;
		}
	}
	nret = UnlockCommonPoolFetchMutex( pool ) ;
	if( nret )
		return COMMONPOOL_ERROR_MUTEX;
	
	(*session_ctx) = session->session_ctx ;
	return COMMONPOOL_ERROR_SUCCESS;
}

int JustFetchCommonPoolIdleSession( struct CommonPool *pool , void **session_ctx )
{
	struct CommonPoolSession	*session = NULL ;
	int				nret = 0 ;
	
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
	if( pool->status == COMMONPOOL_STATUS_RUNNING )
		;
	else
		return COMMONPOOL_ERROR_POOL_STATUS;
	
	nret = LockCommonPoolFetchMutex( pool ) ;
	if( nret )
		return COMMONPOOL_ERROR_MUTEX;
	/* pthread mutex */
	{
		if( pool->idle_sessions_count > 0 )
		{
			session = list_last_entry_or_null( & (pool->idle_sessions_list) , struct CommonPoolSession , session_list_node ) ;
			if( session == NULL )
			{
				UnlockCommonPoolFetchMutex( pool );
				return COMMONPOOL_ERROR_INTERNAL;
			}
			
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : fetch session[%p] last_excited_secondstamp[%ld] idle_sessions_count[%zu]->[%zu] working_sessions_count[%zu]->[%zu]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session , session->last_excited_secondstamp , pool->idle_sessions_count , pool->idle_sessions_count-1 , pool->working_sessions_count , pool->working_sessions_count+1 ); fflush(stdout);
#endif
			IdleSession2Working( pool , session );
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : fetch session[%p] IdleSession2Working\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session ); fflush(stdout);
#endif
		}
		else
		{
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : too many sessions , idle_sessions_count[%zu] working_sessions_count[%zu]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool->idle_sessions_count , pool->working_sessions_count ); fflush(stdout);
#endif
			UnlockCommonPoolFetchMutex( pool );
			return COMMONPOOL_ERROR_NO_IDLE_SESSION;
		}
	}
	nret = UnlockCommonPoolFetchMutex( pool ) ;
	if( nret )
		return COMMONPOOL_ERROR_MUTEX;
	
	(*session_ctx) = session->session_ctx ;
	return COMMONPOOL_ERROR_SUCCESS;
}

int GivebackCommonPoolSession( struct CommonPool *pool , void *session_ctx )
{
	struct CommonPoolSession	*session = (struct CommonPoolSession *)( (char*)session_ctx - sizeof(struct CommonPoolSession) ) ;
	int				nret = 0 ;
	
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
	if( pool->status == COMMONPOOL_STATUS_RUNNING || pool->status == COMMONPOOL_STATUS_STOPING )
		;
	else
		return COMMONPOOL_ERROR_POOL_STATUS;
	
	nret = LockCommonPoolFetchMutex( pool ) ;
	if( nret )
		return COMMONPOOL_ERROR_MUTEX;
	/* pthread mutex */
	{
#if __DEBUG
if( pool->status != COMMONPOOL_STATUS_RUNNING )
{
printf( "commonpool | %010lu | %s:%d | commonpool.%s : giveback session[%p] working_sessions_count[%zu]->[%zu]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session , pool->working_sessions_count , pool->working_sessions_count-1 ); fflush(stdout);
}
else
{
printf( "commonpool | %010lu | %s:%d | commonpool.%s : giveback session[%p] idle_sessions_count[%zu]->[%zu] working_sessions_count[%zu]->[%zu]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session , pool->idle_sessions_count , pool->idle_sessions_count+1 , pool->working_sessions_count , pool->working_sessions_count-1 ); fflush(stdout);
}
#endif
		WorkingSession2Idle( pool , session );
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : giveback session[%p] WorkingSession2Idle\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session ); fflush(stdout);
#endif
	}
	nret = UnlockCommonPoolFetchMutex( pool ) ;
	if( nret )
		return COMMONPOOL_ERROR_MUTEX;
	
	return COMMONPOOL_ERROR_SUCCESS;
}

int ReleaseCommonPoolIdleSession( struct CommonPool *pool , void *session_ctx )
{
	struct CommonPoolSession	*session = (struct CommonPoolSession *)( (char*)session_ctx - sizeof(struct CommonPoolSession) ) ;
	int				nret = 0 ;
	
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : pool[%p]->status[%s]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , pool , sg_commonpool_status_str[pool->status] ); fflush(stdout);
#endif
	nret = LockCommonPoolFetchMutex( pool ) ;
	if( nret )
		return COMMONPOOL_ERROR_MUTEX;
	/* pthread mutex */
	{
		list_del( & (session->session_list_node) );
		pool->idle_sessions_count--;
		
		nret = DestroyCommonPoolSession( pool , session ) ;
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : DestroyCommonPoolSession return[%d]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , nret ); fflush(stdout);
#endif
	}
	nret = UnlockCommonPoolFetchMutex( pool ) ;
	if( nret )
		return COMMONPOOL_ERROR_MUTEX;
	
	return nret;
}

size_t GetCommonPoolIdleSessionsCount( struct CommonPool *pool )
{
	return pool->idle_sessions_count;
}

size_t GetCommonPoolWorkingSessionsCount( struct CommonPool *pool )
{
	return pool->working_sessions_count;
}

#if 0
void *TravelCommonPoolIdleSession( struct CommonPool *pool , void *session_ctx , unsigned char change_status_idle2working )
{
	struct CommonPoolSession	*session = NULL ;
	
	if( session_ctx == NULL )
	{
		session = list_first_entry_or_null( & (pool->idle_sessions_list) , struct CommonPoolSession , session_list_node ) ;
	}
	else
	{
		session = (struct CommonPoolSession *)( (char*)session_ctx - sizeof(struct CommonPoolSession) ) ;
		session = list_next_entry_or_null( session , & (pool->idle_sessions_list) , struct CommonPoolSession , session_list_node ) ;
	}
#if __DEBUG
printf( "commonpool | %010lu | %s:%d | commonpool.%s : travel session[%p]->session_ctx[%p]\n" , (unsigned long)pthread_self() , __FILE__,__LINE__,__FUNCTION__ , session , session->session_ctx ); fflush(stdout);
#endif
	
	if( session == NULL )
	{
		return NULL;
	}
	else
	{
		if( change_status_idle2working )
			IdleSession2Working( pool , session );
		
		return session->session_ctx;
	}
}

void ChangebackAfterTravelCommonPoolSession( struct CommonPool *pool , void *session_ctx )
{
	struct CommonPoolSession	*session = (struct CommonPoolSession *)( (char*)session_ctx - sizeof(struct CommonPoolSession) ) ;
	
	WorkingSession2Idle( pool , session );
	
	return;
}
#endif

